/*
 * Decompiled with CFR 0.146.
 * 
 * Could not load the following classes:
 *  net.minecraft.util.ResourceLocation
 *  net.minecraftforge.client.model.IModelCustom
 *  org.lwjgl.opengl.GL11
 */
package mogiksaop.qliphoth.client.models.smd;

import mogiksaop.qliphoth.common.Qliphoth;
import mogiksaop.qliphoth.common.util.RegexPatterns;
import mogiksaop.qliphoth.client.models.IQliphothModel;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.block.model.IBakedModel;
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
import net.minecraft.client.renderer.vertex.VertexFormat;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.client.model.IModel;
import net.minecraftforge.common.model.IModelState;

public class ValveStudioModel implements IModel, IQliphothModel {
	public static boolean debugModel = false;
	public SmdModel body;
	protected Bone root;
	ArrayList<Bone> allBones;
	public SmdAnimationSequence currentSequence;
	public ResourceLocation resource;
	public boolean overrideSmoothShading;
	public boolean hasChanged;
	private boolean hasAnimations;
	public HashMap<String, SmdAnimationSequence> anims;
	protected String materialPath;
	protected boolean usesMaterials;
	private float scale;

	public ValveStudioModel(ValveStudioModel model) {
		this.overrideSmoothShading = false;
		this.hasChanged = true;

		this.hasAnimations = false;
		this.anims = new HashMap(4);

		this.usesMaterials = false;

		this.scale = -1.0F;

		this.body = new SmdModel(model.body, this);
		for (Map.Entry<String, SmdAnimationSequence> entry : model.anims.entrySet()) {
			this.anims.put(entry.getKey(),
					new SmdAnimationSequence(((SmdAnimationSequence) entry.getValue()).sequence, this));
		}
		this.hasAnimations = model.hasAnimations;
		this.usesMaterials = model.usesMaterials;
		this.scale = model.scale;
		this.resource = model.resource;
		this.currentSequence = (SmdAnimationSequence) this.anims.get("idle");
		this.overrideSmoothShading = model.overrideSmoothShading;
	}

	public ValveStudioModel(ResourceLocation resource, boolean overrideSmoothShading) throws GabeNewellException {
		this.overrideSmoothShading = false;
		this.hasChanged = true;
		this.hasAnimations = false;
		this.anims = new HashMap(4);
		this.usesMaterials = false;
		this.scale = -1.0F;
		this.overrideSmoothShading = overrideSmoothShading;
		this.resource = resource;
		System.out.println("各参数已填入！准备进入loadQC阶段！");
		loadQC(resource);
		reformBones();
		precalculateAnimations();
	}

	public ValveStudioModel(ResourceLocation resource) throws GabeNewellException {
		this(resource, false);
		System.out.println("成功初始化vs模型的构造！");
	}

	public float getScale() {
		return this.scale;
	}

	public boolean hasAnimations() {
		return this.hasAnimations;
	}

	private void precalculateAnimations() {
		for (SmdAnimationSequence anim : this.anims.values()) {
			anim.precalculate(this.body);
		}
	}

	public void renderAll() {
		GlStateManager.shadeModel(7425);
		try {
			this.body.render(this.hasChanged);
		} catch (Exception e) {
			e.printStackTrace();
			if (OpenGlHelper.useVbo()) {
				OpenGlHelper.glBindBuffer(OpenGlHelper.GL_ARRAY_BUFFER, 0);
			}
		}
		GlStateManager.shadeModel(7424);
	}

	void sendBoneData(SmdModel model) {
		this.allBones = model.bones;
		if (!model.isBodyGroupPart)
			this.root = model.root;
	}

	private void reformBones() {
		this.root.reformChildren();
		this.allBones.forEach(Bone::invertRestMatrix);
	}

	public void animate() {
		resetVerts(this.body);
		if (this.body.currentAnim == null)
			setAnimation("idle");
		this.root.setModified();
		this.allBones.forEach(Bone::applyModified);
		applyVertChange(this.body);
		this.hasChanged = true;
	}

	public void setAnimation(String animName) {
		if (this.anims.containsKey(animName)) {
			this.currentSequence = (SmdAnimationSequence) this.anims.get(animName);
		} else {
			this.currentSequence = (SmdAnimationSequence) this.anims.get("idle");
		}
		if (this.currentSequence != null) {
			this.body.setAnimation(this.currentSequence.current());
		} else {
			this.body.setAnimation(null);
		}

	}

	protected String getMaterialPath(String subFile) {
		String result = "/assets/qliphoth";
		if (!this.materialPath.startsWith("/"))
			result = result + "/";
		result = result + this.materialPath;
		if (!subFile.startsWith("/"))
			result = result + "/";
		result = result + subFile;
		int lastDot = result.lastIndexOf(".");
		return (lastDot == -1) ? (result + ".mat") : (result.substring(0, lastDot) + ".mat");
	}

	private void resetVerts(SmdModel model) {
		if (model == null)
			return;
		model.verts.forEach(DeformVertex::reset);
	}

	private void applyVertChange(SmdModel model) {
		if (model == null)
			return;
		model.verts.forEach(DeformVertex::applyChange);
	}

	public Collection<ResourceLocation> getDependencies() {
		return null;
	}

	public Collection<ResourceLocation> getTextures() {
		return null;
	}

	public IBakedModel bake(IModelState state, VertexFormat format, Function<ResourceLocation, TextureAtlasSprite> bakedTextureGetter) {
		return null;
	}

	public IModelState getDefaultState() {
		return null;
	}

	public static void print(Object o) {
		if (debugModel)
			System.out.println(o);
	}

	private void loadQC(ResourceLocation resource) throws GabeNewellException {
		//origin: InputStream
		System.out.println("开始读取输入流！");
		BufferedInputStream inputStream = Qliphoth.proxy.getStreamForResourceLocation(resource);
		int lineCount = 0;
		System.out.println("目前输入流路径：" + "/assets/" + resource.getNamespace() + "/" + resource.getPath());
		
		System.out.println("输入流对象目前为：" + inputStream + "，resource目前为：" + resource);
		 
		try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {

			String[] bodyParams = null;
			ArrayList<String[]> animParams = new ArrayList<String[]>();
			System.out.println("开始读取pqc文件！");
			String currentLine;
			while ((currentLine = reader.readLine()) != null) {
				lineCount++;
				System.out.println("当前为第"+ lineCount +"行");
				String[] params = RegexPatterns.MULTIPLE_WHITESPACE.split(currentLine);
				if (params[0].equalsIgnoreCase("$body")) {
					bodyParams = params;
					continue;
				}
				if (params[0].equalsIgnoreCase("$anim")) {
					this.hasAnimations = true;
					animParams.add(params);
					continue;
				}
				if (params[0].equalsIgnoreCase("$cdmaterials")) {
					this.usesMaterials = true;
					this.materialPath = params[1];
					continue;
				}
				if (params[0].equalsIgnoreCase("$scale")) {
					this.scale = Float.parseFloat(params[1]);
				}
			}
			if (this.scale == -1.0F) {
				this.scale = 1.0F;
				if (this.resource.getPath().startsWith("models/entity/qliphoth")) {
					Qliphoth.LOGGER.error("Model " + resource.getPath() + " did not have a scale specified!");
				}
			}

			System.out.println("读取pqc文件成功！");
			
			System.out.println("开始填入参数！");
			
			ResourceLocation modelPath = getResource(bodyParams[1]);
			System.out.println("模型路径目前为："+modelPath+"，躯体参数1："+bodyParams[1]);
			this.body = new SmdModel(this, modelPath);
			System.out.println("模型绑定实体躯干成功！");
			HashMap<ResourceLocation, SmdAnimation> recognizedAnimations = new HashMap<ResourceLocation, SmdAnimation>();
			System.out.println("模型映射表建立成功！");
			for (String[] animPars : animParams) {
				String animName = animPars[1];
				System.out.println("动画名称："+animName);
				List<SmdAnimation> sequence = new ArrayList<SmdAnimation>();
				for (int i = 2; i < animPars.length; i++) {
					ResourceLocation animPath = getResource(animPars[i]);
					if (recognizedAnimations.containsKey(animPath)) {
						sequence.add(recognizedAnimations.get(animPath));
					} else {
						SmdAnimation animation = new SmdAnimation(this, animName, animPath);
						sequence.add(animation);
						recognizedAnimations.put(animPath, animation);
					}
				}

				this.anims.put(animName, new SmdAnimationSequence(sequence, this));
				if (animName.equalsIgnoreCase("idle")) {
					this.currentSequence = (SmdAnimationSequence) this.anims.get(animName);
				}
			}

			System.out.println("参数填入成功！");
			
		} catch (GabeNewellException e) {
			throw e;
		} catch (Exception e) {
			throw new GabeNewellException("An error occurred while reading the " + resource.toString() + " PQC file on line #" + lineCount, e);
		}
	}

	public ResourceLocation getResource(String fileName) {
		String urlAsString = this.resource.getPath();
		int lastIndex = urlAsString.lastIndexOf('/');
		String startString = urlAsString.substring(0, lastIndex);
		return new ResourceLocation("qliphoth", startString + "/" + fileName);
	}
}
